package testconditionsAPI;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import conditionsAPI.AndDomainCondition;
import conditionsAPI.ConditionDuplicatedException;
import conditionsAPI.ConditionsConfiguration;
import conditionsAPI.NotDomainCondition;
import conditionsAPI.SimpleDomainCondition;

public class TestAndDomainCondition {
	
	private AndDomainCondition andCondition1;
	private AndDomainCondition andCondition2;
	private SimpleDomainCondition simpleCondition1;
	private SimpleDomainCondition simpleCondition2;
	private SimpleDomainCondition simpleCondition3;
	private SimpleDomainCondition simpleCondition4;

	@Before
	public void setUp(){
		try {
			
			this.andCondition1 = new AndDomainCondition("and1");
			this.andCondition2 = new AndDomainCondition("and2");
			this.simpleCondition1 = new StubSimpleDomainCondition("cond1");
			this.simpleCondition2 = new StubSimpleDomainCondition("cond2");
			this.simpleCondition3 = new StubSimpleDomainCondition("cond3");
			this.simpleCondition4 = new StubSimpleDomainCondition("cond4");
			
		} catch (ConditionDuplicatedException e) {
			e.printStackTrace();
		}
	}
	
	@After
	public void tearDown(){
		ConditionsConfiguration.reset();
	}
	
	@Test
	public void createTwoAndConditionWithSameNameAndThrowException(){
		@SuppressWarnings("unused")
		AndDomainCondition andConditionTwin = null;
		try {
			andConditionTwin = new AndDomainCondition("and1");
			assertTrue(false);
		} catch (ConditionDuplicatedException e) {
			assertTrue(true);
		}
	}
	
	@Test
	public void addPreConditionTwiceGetFalseResult(){
		this.andCondition1.addPreCondition(this.simpleCondition1);
		
		assertFalse(this.andCondition1.addPreCondition(this.simpleCondition1));
	}
	
	@Test
	public void addAndRemovePreConditionGetTrueResult(){
		this.andCondition1.addPreCondition(this.simpleCondition1);
		
		assertTrue(this.andCondition1.removePreCondition(this.simpleCondition1));
	}
	
	@Test
	public void removeNonexistentPreConditionGetFalseResult(){
		assertFalse(this.andCondition1.removePreCondition(this.simpleCondition1));
	}
	
	@Test
	public void processComposedConditionGetFalseResult(){
		ConditionsConfiguration.processObject(this.andCondition1);
		
		assertFalse("A composed condition can never be changed explicitly",this.andCondition1.isTrue());
	}
	
	@Test
	public void addPreConditionsAllPreConditionsFulfilledGetAndConditionIsTrue(){
		this.andCondition1.addPreCondition(this.simpleCondition1);
		this.andCondition1.addPreCondition(this.simpleCondition2);
		
		ConditionsConfiguration.processObject(this.simpleCondition1);
		ConditionsConfiguration.processObject(this.simpleCondition2);
		
		assertTrue(this.andCondition1.isTrue());
	}
	
	@Test
	public void addPreConditionsSomePreConditionsFulfilledGetAndConditionIsFalse(){
		this.andCondition1.addPreCondition(this.simpleCondition1);
		this.andCondition1.addPreCondition(this.simpleCondition2);
		
		ConditionsConfiguration.processObject(this.simpleCondition1);
		
		assertFalse(this.andCondition1.isTrue());
	}
	
	@Test
	public void addAndRemovePreConditionPreConditionFulfilledGetAndConditionIsFalse(){
		this.andCondition1.addPreCondition(this.simpleCondition1);
		this.andCondition1.removePreCondition(this.simpleCondition1);
		
		ConditionsConfiguration.processObject(this.simpleCondition1);
		
		assertFalse(this.andCondition1.isTrue());
	}

	@Test
	public void setTreeWithCircularReferenceAllPreConditionsFulfilledGetAndConditionsAreFalse(){
		this.andCondition1.addPreCondition(this.simpleCondition1);
		this.andCondition1.addPreCondition(this.andCondition2);	
		this.andCondition2.addPreCondition(this.simpleCondition2);
		this.andCondition2.addPreCondition(this.andCondition1);
		
		ConditionsConfiguration.processObject(this.simpleCondition1);
		ConditionsConfiguration.processObject(this.simpleCondition2);
		
		assertFalse("A circular reference of conditions can never be fulfilled",this.andCondition1.isTrue());
		assertFalse("A circular reference of conditions can never be fulfilled",this.andCondition2.isTrue());
	}

	@Test 
	public void addPreConditionsEnableOrderedConditionAllPreConditionsFulfilledInOrderGetAndConditionIsTrue(){
		this.andCondition1.addPreCondition(this.simpleCondition1);
		this.andCondition1.addPreCondition(this.simpleCondition2);
		this.andCondition1.enableConditionOrder();
		
		ConditionsConfiguration.processObject(this.simpleCondition1);
		ConditionsConfiguration.processObject(this.simpleCondition2);
		
		assertTrue(this.andCondition1.isTrue());
	}
	
	@Test 
	public void addPreConditionsEnableOrderedConditionAllPreConditionsNotFulfilledInOrderGetAndConditionIsFalse(){
		this.andCondition1.addPreCondition(this.simpleCondition1);
		this.andCondition1.addPreCondition(this.simpleCondition2);
		this.andCondition1.enableConditionOrder();
		
		ConditionsConfiguration.processObject(this.simpleCondition2);
		ConditionsConfiguration.processObject(this.simpleCondition1);
		
		assertFalse(this.andCondition1.isTrue());
	}
	
	@Test 
	public void addPreConditionsEnableOrderedConditionAllPreConditionsNotFulfilledInOrderDisableOrderedConditionGetAndConditionIsTrue(){
		this.andCondition1.addPreCondition(this.simpleCondition1);
		this.andCondition1.addPreCondition(this.simpleCondition2);
		this.andCondition1.enableConditionOrder();
		
		ConditionsConfiguration.processObject(this.simpleCondition2);
		ConditionsConfiguration.processObject(this.simpleCondition1);
		this.andCondition1.disableConditionOrder();
		
		assertTrue(this.andCondition1.isTrue());
	}
	
	@Test 
	public void addPreConditionsEnableOrderedConditionAllPreConditionsFulfilledInOrderAndCancelledGetAndConditionIsFalse(){
		this.andCondition1.addPreCondition(this.simpleCondition1);
		this.andCondition1.addPreCondition(this.simpleCondition2);
		this.andCondition1.addPreCondition(this.simpleCondition3);
		
		NotDomainCondition notCondition = null;
		try {
			notCondition = new NotDomainCondition(this.simpleCondition2);
		} catch (ConditionDuplicatedException e) {
			e.printStackTrace();
		}
		
		notCondition.addPreCondition(this.simpleCondition4);

		this.andCondition1.enableConditionOrder();
		
		ConditionsConfiguration.processObject(this.simpleCondition1);
		ConditionsConfiguration.processObject(this.simpleCondition2);
		ConditionsConfiguration.processObject(this.simpleCondition3);
		ConditionsConfiguration.processObject(this.simpleCondition4);
		ConditionsConfiguration.processObject(this.simpleCondition2);
		
		assertFalse(this.andCondition1.isTrue());
	}
		
	@Test 
	public void addPreConditionsEnableOrderedConditionAllPreConditionsFulfilledInOrderAndCancelledAndFulfilledInOrderGetAndConditionIsTrue(){
		this.andCondition1.addPreCondition(this.simpleCondition1);
		this.andCondition1.addPreCondition(this.simpleCondition2);
		this.andCondition1.addPreCondition(this.simpleCondition3);
		
		NotDomainCondition notCondition = null;
		try {
			notCondition = new NotDomainCondition(this.simpleCondition2);
		} catch (ConditionDuplicatedException e) {
			e.printStackTrace();
		}
		
		notCondition.addPreCondition(this.simpleCondition4);

		this.andCondition1.enableConditionOrder();
		
		ConditionsConfiguration.processObject(this.simpleCondition1);
		ConditionsConfiguration.processObject(this.simpleCondition2);
		ConditionsConfiguration.processObject(this.simpleCondition3);
		ConditionsConfiguration.processObject(this.simpleCondition4);
		ConditionsConfiguration.processObject(this.simpleCondition2);
		ConditionsConfiguration.processObject(this.simpleCondition3);
		
		assertTrue(this.andCondition1.isTrue());
	}

	@Test 
	public void addThreePreConditionsEnableOrderedConditionTwoPreConditionsFulfilledInOrderRemoveLastPreconditionGetAndConditionIsTrue(){
		this.andCondition1.addPreCondition(this.simpleCondition1);
		this.andCondition1.addPreCondition(this.simpleCondition2);
		this.andCondition1.addPreCondition(this.simpleCondition3);
		this.andCondition1.enableConditionOrder();
		
		ConditionsConfiguration.processObject(this.simpleCondition1);
		ConditionsConfiguration.processObject(this.simpleCondition2);
		this.andCondition1.removePreCondition(this.simpleCondition3);
		
		assertTrue(this.andCondition1.isTrue());
	}
	
}
